
#ifndef RANDOMGENERATOR_H_
#define RANDOMGENERATOR_H_

#include <boost/random/normal_distribution.hpp>
#include <boost/random/exponential_distribution.hpp>
#include <boost/random/uniform_int.hpp>
#include <boost/random/bernoulli_distribution.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/variate_generator.hpp>


class RandomGenerator {

public:

	virtual int getNumber()= 0;

};

class NormalRandomGenerator : public RandomGenerator {

public:

	NormalRandomGenerator(int seed, int min, int max, float scaleStdDev, float incremento): min(min), max(max), igen(seed), gen(igen, boost::normal_distribution<>(((min+max)/2)*incremento,((max-min)/6)*scaleStdDev)) {
		//median = (min+max)/2;
		//stdDev = (max-min)/6;
		//gen(igen, boost::normal_distribution<>(median,stdDev));
	}

	virtual ~NormalRandomGenerator(){ }

	int getNumber(){
		int number = gen();
		if (number < min) number = min;
		else if (number > max) number = max;
		return number;
	}

private:

	int min;
	int max;
	//int median;
	//int stdDev;
	boost::mt19937 igen;
	boost::variate_generator<boost::mt19937, boost::normal_distribution<> > gen;
};


class ExponentialRandomGenerator : public RandomGenerator {

public:

	ExponentialRandomGenerator(int seed, int max, float lambda): max(max), igen(seed), gen(igen, boost::exponential_distribution<>(lambda)) {
		float a = 0.9999;
		float quantile = (1/lambda)*log(1/(1-a));
		scale = max/quantile;
	}

	virtual ~ExponentialRandomGenerator(){ }

	int getNumber(){
		int number = gen()*scale;
		if (number > max) number = max;
		return number;
	}

private:

	float scale;
	//float lambda;
	int max;
	boost::mt19937 igen;
	boost::variate_generator<boost::mt19937, boost::exponential_distribution<> > gen;
};


class UniformRandomGenerator : public RandomGenerator {

public:

	UniformRandomGenerator(int seed, int min, float max): igen(seed), gen(igen, boost::uniform_int<>(min,max))
	{ }

	virtual ~UniformRandomGenerator(){ }

	int getNumber(){
		int number = gen();
		return number;
	}

private:
	boost::mt19937 igen;
	boost::variate_generator<boost::mt19937, boost::uniform_int<> > gen;
};


class BernoulliRandomGenerator : public RandomGenerator {

public:

	BernoulliRandomGenerator(int seed, float p) : igen(seed), gen(igen, boost::bernoulli_distribution<>(p))
	{ }

	virtual ~BernoulliRandomGenerator(){ }

	int getNumber(){
		return gen();
	}

private:

	boost::mt19937 igen;
	boost::variate_generator<boost::mt19937, boost::bernoulli_distribution<> > gen;
};


#endif /* RANDOMGENERATOR_H_ */

